import time

from s_server.tools.data_handler import get_code_kl_state
from s_server.models import *
import math


class MoniDoding(object):
    def __init__(self, code, s_data_list, start_number=1200, start_zijin=100000, times_percent=1, a_times=1.0,
                 b_times=1.0):
        self.window_number = 120
        self.zijin = start_zijin
        self.s_data_list = s_data_list
        self.money_in = 0
        self.money_out = start_zijin
        self.last_all_money = self.money_in + self.money_out
        self.start_number = start_number
        self.current_price_state = {}
        self.code = code
        self.times_percent = float(times_percent)
        self.a_times = a_times
        self.b_times = b_times

    @property
    def current_money(self):
        return self.money_in + self.money_out

    def update_kl_state(self, kl_state):
        return kl_state * self.times_percent

    def run(self):
        shouxu = 0.0005
        yinhua = 0.0005
        if len(self.s_data_list) < self.start_number:
            print("无法模拟")
            return
        # print("START", self.s_data_list[self.start_number - self.window_number:self.start_number][:10])
        # 先做一次
        current_data = self.s_data_list[self.start_number - self.window_number:self.start_number]

        print("################current_data", current_data[0].d, current_data[-1].d, current_data[-1].c)
        self.current_price_state = current_data[-1].c
        print("self.window_number", self.window_number)
        if len(current_data) == self.window_number:
            zd_list = [i.zd for i in current_data]
            kl_state = get_code_kl_state(zd_list, self.a_times, self.b_times)
            self.start_number += 1
            last_state = self.update_kl_state(kl_state)
            print("保持比例 ", last_state, self.start_number)
            print(self.current_price_state)
            print("CODE {} ALL {} IN {} OUT {}".format(self.code, self.last_all_money, self.money_in, self.money_out))
        else:
            return
        while True:
            # print("####",self.start_number - self.window_number,self.start_number)
            current_data = self.s_data_list[self.start_number - self.window_number:self.start_number]
            # print("################current_data", current_data[0].d,current_data[-1].d,current_data[-1].c)
            self.current_price_state = current_data[-1].c

            current_day_zd = float(current_data[-1].zd)
            if float(last_state) < 0:
                # out self.money_in
                _money_in = self.money_in * (1 - yinhua)
                self.money_out = self.money_out + _money_in
                self.last_all_money = self.money_out

                self.money_in = 0.0
            else:
                last_in_money = self.money_in
                last_out_money = self.money_out

                in_money = last_state * (self.last_all_money)
                # 需要入的钱大于池子里面的
                if in_money >= last_in_money:
                    _money_in = last_in_money + (in_money - last_in_money) * (1 - shouxu)
                    self.money_out = last_out_money - (in_money - last_in_money)
                    in_money = _money_in * (1 + current_day_zd / 100)
                    self.money_in = in_money
                    self.last_all_money = self.money_out + self.money_in
                else:
                    _money_in = last_in_money - (last_in_money - in_money)
                    self.money_out = last_out_money + (last_in_money - in_money) * (1 - yinhua)
                    in_money = _money_in * (1 + current_day_zd / 100)
                    self.money_in = in_money
                    self.last_all_money = self.money_out + self.money_in
            print(self.current_price_state)
            print("CODE {} ALL {} IN {} OUT {} PERCENT {} ZD {}".format(self.code, self.last_all_money, self.money_in,
                                                                        self.money_out, last_state,
                                                                        current_day_zd))
            if len(current_data) == self.window_number:
                zd_list = [i.zd for i in current_data]
                kl_state = get_code_kl_state(zd_list, self.a_times, self.b_times)
                self.start_number += 1
                last_state = self.update_kl_state(kl_state)
                print("保持比例 ", last_state, self.start_number)
                # time.sleep(1)
            else:
                print("END", self.s_data_list[self.start_number - self.window_number:self.start_number][-10:])
                break


class MoniClient(object):
    def __init__(self, code, compute_days=[], moni_days=[], start_zijin=100000, times_percent=1, a_times=1.0,
                 b_times=1.0, moni_compute_days=[120, 60, 30], predict_days=[]):
        self.zijin = start_zijin
        # self.s_data_list = s_data_list
        self.money_in = 0
        self.money_out = start_zijin
        self.last_all_money = self.money_in + self.money_out
        self.start_number = 0
        self.current_price_state = {}

        self.code = code
        self.times_percent = float(times_percent)
        self.a_times = a_times
        self.b_times = b_times

        self.compute_days = compute_days
        self.moni_days = moni_days
        self.window_number = len(self.compute_days)
        self.moni_compute_days = moni_compute_days

        self.last_state_list = []
        self.predict_days = predict_days

        self.point_label = 0

    @property
    def current_money(self):
        return self.money_in + self.money_out

    def update_kl_state(self, kl_state):
        return kl_state * self.times_percent

    def run(self):
        shouxu = 0.0005
        yinhua = 0.0005
        compute_data = Record.objects.filter(
            dm_id_id=self.code,
            d__in=self.compute_days
        )
        moni_data = Record.objects.filter(
            dm_id_id=self.code,
            d__in=self.moni_days
        )
        preidct_data = Record.objects.filter(
            dm_id_id=self.code,
            d__in=self.predict_days
        )
        # print("111111111111111111111111111111$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$")
        # print(len(compute_data),len(moni_data),len(preidct_data))
        # print(compute_data[0].d,compute_data[len(compute_data)-1].d)
        # print(moni_data[0].d, moni_data[len(moni_data)-1].d)
        # print(preidct_data[0].d, preidct_data[len(preidct_data)-1].d)
        # print("222222222222222222222222222222$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$")

        could_moni_data = [
                              {"c": data.c,
                               "zd": data.zd,
                               "d": data.d} for data in compute_data
                          ] + [
                              {"c": data.c,
                               "zd": data.zd,
                               "d": data.d} for data in moni_data
                          ]

        # 计算预测部分的信息
        cloud_predict_data = [
            {"c": data.c,
             "zd": data.zd,
             "d": data.d} for data in preidct_data
        ]
        self.could_moni_data = could_moni_data
        self.cloud_predict_data = cloud_predict_data

        last_point = float(could_moni_data[-1]["c"])

        max_point = max([float(i["c"]) for i in cloud_predict_data])
        if (max_point - last_point) / last_point > 0.05:
            self.point_label = 1
        else:
            self.point_label = 0

        self.last_zd_list = [data.zd for data in moni_data]

        print("计算的总长度", len(could_moni_data))
        compute_list = could_moni_data[self.start_number:self.start_number + self.window_number]
        # print("计算的日期信息")
        # for i in compute_list:
        #     print(i)
        # self.window_number

        self.current_price_state = compute_list[-1]["c"]
        current_day = compute_list[-1]["d"]
        print(
            "日期 {} 当日价格 {} 涨跌 {}".format(current_day, compute_list[-1]["c"], compute_list[-1]["zd"]))

        if len(compute_list) == self.window_number:
            zd_list = [i["zd"] for i in compute_list]
            kl_state = get_code_kl_state(self.moni_compute_days, zd_list, self.a_times, self.b_times)
            last_state = self.update_kl_state(kl_state)
            self.last_state_list.append(last_state)
            print("######### 最终计算的投资比例为", current_day, last_state)
        else:
            return

        while True:
            self.start_number += 1
            # print("####",self.start_number - self.window_number,self.start_number)
            compute_list = could_moni_data[self.start_number:self.start_number + self.window_number]
            # print("################current_data", current_data[0].d,current_data[-1].d,current_data[-1].c)

            if len(compute_list) != self.window_number:
                break

            # print("计算的日期信息")
            # for i in compute_list:
            #     print(i)
            self.current_price_state = compute_list[-1]["c"]
            current_day_zd = float(compute_list[-1]["zd"])
            current_day = compute_list[-1]["d"]
            print(
                "日期 {} 当日价格 {} 涨跌 {}".format(current_day, compute_list[-1]["c"], compute_list[-1]["zd"]))
            # 判断上一天的比例信息
            if float(last_state) < 0:
                _money_in = self.money_in * (1 - yinhua)
                self.money_out = self.money_out + _money_in
                self.last_all_money = self.money_out
                self.money_in = 0.0
            else:
                last_in_money = self.money_in
                last_out_money = self.money_out

                in_money = last_state * (self.last_all_money)
                # 需要入的钱大于池子里面的
                if in_money >= last_in_money:
                    _money_in = last_in_money + (in_money - last_in_money) * (1 - shouxu)
                    self.money_out = last_out_money - (in_money - last_in_money)
                    in_money = _money_in * (1 + current_day_zd / 100)
                    self.money_in = in_money
                    self.last_all_money = self.money_out + self.money_in
                else:
                    _money_in = last_in_money - (last_in_money - in_money)
                    self.money_out = last_out_money + (last_in_money - in_money) * (1 - yinhua)
                    in_money = _money_in * (1 + current_day_zd / 100)
                    self.money_in = in_money
                    self.last_all_money = self.money_out + self.money_in
            # print(self.current_price_state)
            print("日期 {} CODE {} 总资产 {} 内部资产 {} 外部资产 {} 新比例 {} 涨跌幅 {}".format(
                compute_list[-1]["d"],
                self.code,
                self.last_all_money,
                self.money_in,
                self.money_out,
                last_state,
                current_day_zd))

            zd_list = [i["zd"] for i in compute_list]
            kl_state = get_code_kl_state(self.moni_compute_days, zd_list, self.a_times, self.b_times)
            last_state = self.update_kl_state(kl_state)
            self.last_state_list.append(last_state)


def moni_by_code(code, start_number, start_money, times_percent, a=1.0, b=1.0):
    moni_st = Record.objects.filter(dm_id_id=code).all()
    moni = MoniDoding(code, moni_st, start_number, start_money, times_percent, a, b)
    moni.run()
    return moni.last_all_money


def moni_by_code_with_range_day(data):
    code = data["code"]
    # start_compute_day = data["start_compute_day"]
    # end_compute_day = data["end_compute_day"]
    compute_days = data["compute_days"]
    # start_moni_day = data["start_moni_day"]
    # end_moni_day = data["end_moni_day"]
    moni_days = data["moni_days"]
    # print(compute_days,moni_days,"11111111111111")
    times_percent = data["times_percent"]
    a = data["a_times"]
    b = data["b_times"]
    all_money = data["all_money"]
    moni_compute_days = data["moni_compute_days"]
    predict_days = data["predict_days"]

    # moni_st = Record.objects.filter(dm_id_id=code).all()
    moni = MoniClient(code, compute_days, moni_days, all_money, times_percent, a, b, moni_compute_days, predict_days)
    moni.run()
    # print(moni.last_state_list)
    moni.last_state_list = moni.last_state_list[1:]
    # print("计算最后结果 ################################")
    # print(len(moni.last_zd_list))
    # print(len(moni.last_state_list))
    # print(moni.last_state_list)

    return moni.last_all_money, moni.last_zd_list, moni.last_state_list, moni.point_label, moni.could_moni_data, moni.cloud_predict_data
